package org.hcf.utils.excel.poi.base.exp;


import lombok.Getter;
import lombok.Setter;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.DefaultIndexedColorMap;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.hcf.utils.excel.poi.base.exp.header.TableHeader;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import java.util.List;
import java.util.Objects;


@Getter
@Setter
public abstract class SimpleExcelHelper<T> {
    public static final int DEFAULT_ROWS = 10*1000;

    /** excel 的workbook对象  */
    protected Workbook workbook;
    /** 数据页 */
    protected Sheet sheet;
    /** 表头的字体 */
    protected Font defaultHeadFont;
    /** 表头的样式 */
    protected XSSFCellStyle defaultHeadCellStyle;
    /** 表头的列名s */
    protected List<TableHeader<T>> headers;
    /** 下拉选的辅助工具类 */
    protected List<ValidationDataHandler> validationDataHandlers;
    /** 表头行*/
    protected Row headRow;

    /* 数据行的样式 */
    protected CellStyle defaultDataCellStyle;
    /** 数据行的字体样式 */
    protected Font defaultDataFont;

    protected int initRow = DEFAULT_ROWS;

    public List<TableHeader<T>> getHeaders(){
        if(CollectionUtils.isEmpty(this.headers)){
            this.headers = initHeaders();
        }
        return this.headers;
    }
    /**
     * 初始化excel文件的头部信息
     * @return List<TableHeader<T>>
     */
    protected abstract List<TableHeader<T>> initHeaders();

    public List<ValidationDataHandler> getValidationDataHandlers(){
        if(CollectionUtils.isEmpty(this.validationDataHandlers)){
            this.validationDataHandlers = initValidationDataHandlers();
        }
        return this.validationDataHandlers;
    }

    /** 初始化 具体的下拉选*/
    public abstract List<ValidationDataHandler> initValidationDataHandlers();

    /**
     * 创建后， 初始化的入口
     */
    public void initExcelHelper(String sheetName){
        this.getHeaders();
        this.initSXSSFWorkbook();
        this.initDataSheet(sheetName);
        this.initDefaultHeadCellStyle();
        this.initDefaultHeadFont();
        this.initDefaultDataCellStyle();
        this.initHeadRow();
    }

    /** 初始化工作 目录 */
    public Workbook initSXSSFWorkbook(){
        if(!Objects.isNull(workbook)){
            return this.workbook;
        }
        // 大数据量的到处使用这个 带有落地缓存文件的 workbook 对象
        workbook = new SXSSFWorkbook(100);
        return workbook;
    }

    public Sheet initDataSheet(String dateSheetName){
        if(!Objects.isNull(this.sheet)){
            return this.sheet;
        }
        sheet = this.workbook.createSheet(dateSheetName);
        return sheet;
    }

    /** 创建头部Cell的样式 */
    public CellStyle initDefaultHeadCellStyle(){
        if(!Objects.isNull(defaultHeadCellStyle)){
            return defaultHeadCellStyle;
        }
        defaultHeadCellStyle =(XSSFCellStyle) workbook.createCellStyle();
        defaultHeadCellStyle.setBorderBottom(BorderStyle.THIN);
        defaultHeadCellStyle.setBorderLeft(BorderStyle.THIN);
        defaultHeadCellStyle.setBorderRight(BorderStyle.THIN);
        defaultHeadCellStyle.setBorderTop(BorderStyle.THIN);
        // 根据RGB创建背景色
        defaultHeadCellStyle.setFillForegroundColor(new XSSFColor(new java.awt.Color(237,221,158)));
        defaultHeadCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        defaultHeadCellStyle.setAlignment(HorizontalAlignment.CENTER);
        // 单元格样式使用字体
        defaultHeadCellStyle.setFont(initDefaultHeadFont());
        return defaultHeadCellStyle;
    }

    public Font initDefaultHeadFont(){
        if(!Objects.isNull(defaultHeadFont)){
            return defaultHeadFont;
        }
        defaultHeadFont = (XSSFFont) workbook.createFont();
        // 设置头部字体为宋体
        defaultHeadFont.setFontName("宋体");
        defaultHeadFont.setBold(true);
        defaultHeadFont.setFontHeightInPoints((short) 11);
        return defaultHeadFont;
    }

    public CellStyle initDefaultDataCellStyle(){
        if(Objects.nonNull(defaultDataCellStyle)){
            return defaultDataCellStyle;
        }
        defaultDataCellStyle = (XSSFCellStyle) workbook.createCellStyle();
        defaultDataCellStyle.setBorderBottom(BorderStyle.THIN);
        defaultDataCellStyle.setBorderLeft(BorderStyle.THIN);
        defaultDataCellStyle.setBorderRight(BorderStyle.THIN);
        defaultDataCellStyle.setBorderTop(BorderStyle.THIN);
        defaultDataCellStyle.setAlignment(HorizontalAlignment.CENTER);
        // 单元格样式使用字体
        defaultDataCellStyle.setFont(initDataFont());
        return defaultDataCellStyle;
    }

    public Font initDataFont(){
        if(!Objects.isNull(defaultDataFont)){
            return defaultDataFont;
        }
        defaultDataFont = (XSSFFont) workbook.createFont();
        // 设置头部字体为宋体
        defaultDataFont.setFontName("宋体");
        defaultDataFont.setFontHeightInPoints((short) 10);
        return defaultDataFont;
    }

    public Row initHeadRow(){
        if(!Objects.isNull(headRow)){
            return headRow;
        }
        if(Objects.isNull(sheet)){
            throw new RuntimeException("当前sheet对象为空！请先初始化");
        }
        headRow = sheet.createRow(sheet.getPhysicalNumberOfRows());
        /*对每一个单元格进行初始化*/
        for (int i=0; i<headers.size(); i++){
            TableHeader tableHeader = headers.get(i);
            String colName = tableHeader.getFieldName();
            int width = tableHeader.getWidth();
            if(Objects.isNull(colName) || "".equals(colName)){
                continue;
            }
            Cell headerCell = headRow.createCell(i);
            headerCell.setCellValue(colName);
            // header 进行初始化一下头部Cell的样式
            tableHeader.initHeadCellStyle(headerCell, this);
            if(width > 0){
                this.sheet.setColumnWidth(i,width);
            }
        }
        return headRow;
    }

    public void  outData(Collection<T> rows){
        int i = 0;
        for (T t: rows){
            if(Objects.isNull(t)){
                continue;
            }
            i++;
            Row row = sheet.createRow(sheet.getPhysicalNumberOfRows());
            for(TableHeader header:headers) {
                Cell dateCell = row.createCell(row.getPhysicalNumberOfCells());
                dateCell.setCellStyle(defaultDataCellStyle);
                // outDate
                if(Objects.nonNull(t)) {
                    header.dataCellout(dateCell, t);
                }
            }
        }
        initDefaultRow(i);
    }

    public void initDefaultRow(int currentRow){
        if(currentRow<=0){
            currentRow=1;
        }
        while(currentRow<initRow){
            Row row = sheet.createRow(currentRow++);
            int cellNo = 0;
            int size = headers.size();
            while (cellNo<size){
                Cell dateCell = row.createCell(cellNo++);
                dateCell.setCellStyle(defaultDataCellStyle);
            }
        }
    }

    /** 请先初始化相关的validationDatas再调用*/
    public void setDataValidation(){
        List<ValidationDataHandler> handlers = this.getValidationDataHandlers();
        if(CollectionUtils.isEmpty(handlers)){
            return;
        }
        for (ValidationDataHandler handler : handlers) {
            if(Objects.isNull(handler)){
                continue;
            }
            handler.setDataValidation();
        }

    }

    public void outFile(String fileNameURL) throws IOException {
        File f = new File(fileNameURL);
        File parent = f.getParentFile();
        if(!parent.exists()){
            parent.mkdirs();
        }
        FileOutputStream fos = new FileOutputStream(f);
        outFile(fos);
    }

    public void outFile(OutputStream outputStream) throws IOException {
        this.workbook.write(outputStream);
        this.close();
    }

 /*   public void downloadExcelFile(HttpServletResponse response, String fileName) throws IOException {
        response.setHeader("Content-Disposition", "attachment;filename=".concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8"))));
        response.setHeader("Connection", "close");
        response.setHeader("Content-Type", "application/vnd.ms-excel");
        OutputStream os = response.getOutputStream();
        this.workbook.write(os);

        this.close();
    }*/

    public void close(){
        if(!Objects.isNull(workbook)){
            try {
                workbook.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        this.workbook = null;
        this.sheet = null;
        this.defaultHeadCellStyle = null;
        this.defaultHeadFont = null;
        this.headRow = null;

        this.defaultDataCellStyle = null;
        this.defaultDataFont =null;
        System.gc();
    }
}